package com.example.tcpConnect;
import ohos.ace.ability.AceInternalAbility;
import ohos.event.commonevent.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.rpc.IRemoteObject;
import ohos.rpc.MessageOption;
import ohos.rpc.MessageParcel;
import ohos.utils.zson.ZSONObject;


import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class tcpConnectTest extends AceInternalAbility {
    private static final String TAG = tcpConnectTest.class.getSimpleName();
    private static final String BUNDLE_NAME="com.example.tcpConnect";
    private static final String ABILITY_NAME="tcpConnectTest";
    public static final String SELF_SOCKET_MSG = "TCP.CLIENT.MSG";
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD000F00, TAG);
    private static final int socket_connet = 1001;
    private static final int socket_send = 1002;
    private static final int socket_submsg = 1003;
    private static final int socket_loopsend = 1012;
    private static final int socket_close = 1004;
    private static final int DEFAULT_TYPE = 0;
    private static tcpConnectTest instance;
    private CommonEventSubscriber subscriber;
    public static Socket socket = null;
    public static OutputStream os = null;
    public static InputStream is = null;
    public static BufferedReader br = null;
    private Set<IRemoteObject> remoteObjectHandlers = new HashSet<IRemoteObject>();


    private static class MyRunnable implements Runnable {

        private boolean running = false;
        private OutputStream output_stream = null;
        private byte[] msg = null;
        public int hz = 10;

        public void setOutputStream(OutputStream os) {
            this.output_stream = os;
        }
        public void setMsg(byte[] msg) {
            this.msg = msg;
        }

        public void setHz(int hz) {
            this.hz = hz;
        }

        @Override
        public void run() {
            this.running = true;
            try {
                while (this.running)
                {
                    this.output_stream.write(this.msg);
                    Thread.sleep(1000 / this.hz);
                }
                Thread.sleep(100);
            } catch (IOException | InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    private MyRunnable loop_send_ru = new MyRunnable();
    private Thread loop_send_td = new Thread(loop_send_ru);

    public tcpConnectTest() {
        super(BUNDLE_NAME, ABILITY_NAME);
    }

    public static tcpConnectTest getInstance(){
        if (instance == null) {
            synchronized (tcpConnectTest.class) {
                if (instance == null) {
                    instance = new tcpConnectTest();
                }
            }
        }
        return instance;
    }
    /*
    Ace注册
     */
    public void register(){
        this.setInternalAbilityHandler(this::onRemoteRequest);
        HiLog.error(LABEL_LOG,"connect started");
    }
    /*
    Ace取消注册
     */
    public void deregister(){
        this.setInternalAbilityHandler(null);
        HiLog.error(LABEL_LOG,"11");
    }
    /*
    Ace回调事件
     */
    public boolean onRemoteRequest(int code,MessageParcel data,MessageParcel reply,MessageOption option){
        switch (code){
            case socket_connet:
                try {
                    if(this.createSocket(data, reply, option)){
                        reply.writeString("socket_create");
                        HiLog.error(LABEL_LOG,"socket_create");
                    } else {
                        reply.writeString("socket_faild");
                    }
                }catch(IOException e){
                    reply.writeString("socket_faild");
                    e.printStackTrace();
                }
                break;
            case socket_send:
                SendMsg(data, reply, option);
                HiLog.error(LABEL_LOG,"socket_send");
                break;
            case socket_loopsend:
                LoopSendMsg(data, reply, option, 5);
                HiLog.error(LABEL_LOG,"socket_loopsend");
                break;
            case socket_submsg: {
                String ret = null;
                int read = 0;
                byte[] bytes = new byte[1024];
                try {
                    read = is.read(bytes);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                ret = new String(bytes, 0, read, Charset.defaultCharset());
                remoteObjectHandlers.add(data.readRemoteObject());
                Map<String, Object> result = new HashMap<String, Object>();
                result.put("data",ret );
                reply.writeString(ZSONObject.toZSONString(result));
                break;
            }
            default:
                HiLog.error(LABEL_LOG,"default");
                reply.writeString("service not defined");
                return false;
        }
        return true;
    }

    private boolean createSocket(MessageParcel data, MessageParcel reply, MessageOption option) throws IOException {
        String dataStr = data.readString();
        SocketAddress param = new SocketAddress();
        if (socket != null) {
            if (socket.isConnected()) {
                socket.close();
            }
        }
        os = null;
        is = null;
        try {
            param = ZSONObject.stringToClass(dataStr, SocketAddress.class);
            socket = new Socket();
            socket.connect(new InetSocketAddress(param.getIp(), param.getPort()), 500);
        } catch (RuntimeException e) {
            HiLog.error(LABEL_LOG, "连接失败");
            return false;
        } catch (SocketTimeoutException e) {
            HiLog.error(LABEL_LOG, "连接超时");
            return false;
        }

        HiLog.error(LABEL_LOG, "连接成功");
        socket.setSoTimeout(20000);
        os = socket.getOutputStream();
        is = socket.getInputStream();
        String msg = "我是：" + socket.getLocalAddress().toString();
        os.write(msg.getBytes(StandardCharsets.UTF_8));
        return true;
    }

    private boolean closeSocket() throws IOException {
        if (socket != null) {
            socket.close();
            return socket.isClosed();
        } else {
            return true;
        }

    }

    private void SendMsg(MessageParcel data, MessageParcel reply, MessageOption option) {
        if (this.loop_send_td.isAlive()) {
            this.loop_send_ru.running = false;
//            this.loop_send_td.join(1000);
        }

        String dataStr=data.readString();
        dataParam param=new dataParam();
        try{
            param=ZSONObject.stringToClass(dataStr,dataParam.class);
        }catch(RuntimeException e){
            HiLog.error(LABEL_LOG,"FAILED");
        }
        try {
            os.write(param.getTest().getBytes(StandardCharsets.UTF_8));
        }catch (UnsupportedEncodingException e){
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void LoopSendMsg(MessageParcel data, MessageParcel reply, MessageOption option, int hz) {
        String dataStr = data.readString();
        dataParam param = new dataParam();
        try {
            param = ZSONObject.stringToClass(dataStr, dataParam.class);
        } catch (RuntimeException e) {
            HiLog.error(LABEL_LOG, "FAILED");
        }
        loop_send_ru.setOutputStream(os);
        loop_send_ru.setMsg(param.getTest().getBytes(StandardCharsets.UTF_8));
        loop_send_ru.setHz(hz);
        loop_send_td = new Thread(loop_send_ru);
        loop_send_td.start();
    }

}
